package rsj.api.user;

import com.alibaba.fastjson.JSON;
import com.rlyy.aibase.os.service.Link;
import com.rlyy.aibase.utils.base.Box;
import com.rlyy.aibase.utils.base.MapNode;
import com.rlyy.aibase.utils.base.ThinkException;
import com.rlyy.aibase.view.key.APIKey_Enum;
import common.entity.ReflexHandler;
import common.exec.BaseException;
import common.exec.RsjServiceWarnException;
import common.util.BoxUtil;
import common.util.UUIDUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import rsj.db.PostgresqlConn;
import rsj.exception.MyExceptionResolver;
import rsj.interceptor.AbstractForwardExport;
import rsj.interceptor.MyInterceptor;
import rsj.log.OperationLog;
import rsj.log.OperationTypeEnum;
import rsj.service.LogInfoService;
import rsj.utils.AesRsjUtil;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

@Component
public class BaseLink implements Link {
    protected static final Logger logger = LoggerFactory.getLogger(BaseLink.class);

    @Autowired
    private MyInterceptor authInterceptor;

    @Autowired
    private AbstractForwardExport forwardExport;

    @Autowired
    private Map<String, ReflexHandler> handlerMapping;

    @Autowired
    private MyExceptionResolver myExceptionResolver;

    @Override
    public Box excute(Box in) throws ThinkException {
        try {
            authInterceptor.preHandle(in);
            // 转发导出报表请求
            if (AbstractForwardExport.isExport(in)) {
                return forwardExport.forwardExport(in);
            }

            ReflexHandler handler = handlerMapping.get(in.getApi());
            if (handler == null) {
                return new Box().setError("Api不存在");
            }
            Box result = (Box) handler.getMethod().invoke(handler.getBean(), in);
            CompletableFuture.runAsync(() -> this.writeLog(in, result, handler));
            return result;
        } catch (Exception e) {
            this.loggerError(in, e, UUIDUtil.getUUID());
            Throwable throwable = e instanceof InvocationTargetException ? ((InvocationTargetException) e).getTargetException() : e;
            return myExceptionResolver.invokeExceptionMethod(in, throwable);
        }
    }

    /**
     * 写日志
     *
     * @param in             参数
     * @param result         返回数据
     * @param requestHandler 请求处理程序
     */
    public void writeLog(Box in, Box result, ReflexHandler requestHandler) {
        Method method = requestHandler.getMethod();
        if (method.isAnnotationPresent(OperationLog.class)) {
            //处理完将日志入库
            LogInfoService infoService = LogInfoService.getInstance();
            MapNode data = in.getMapNode(APIKey_Enum.USER.getKey());
            logger.info("userInfo:\t" + JSON.toJSONString(data));
            OperationLog operationLog = method.getAnnotation(OperationLog.class);
            String description = operationLog.description();
            String location = operationLog.logModule().getMsg();
            String operation = StringUtils.isNotBlank(description) ? description : operationLog.logType().getMsg();
            String level = operationLog.logType().getLevel();
            String content = "";
            if (!level.equals(OperationTypeEnum.LOGIN.getLevel())) {
                content = JSON.toJSONString(in.getMapNode("data").toMap());
            } else {
                data.putNode("User_Id", getUserIdFromToken(result));
            }

            try (Connection conn = PostgresqlConn.getConnection()) {
                infoService.insertLog(conn, data, location, operation, level, content);
            } catch (SQLException e) {
                logger.error("invoke--->" + in.getApi() + " error "
                        + ", arguments is " + in.toJson(), e);
            }
        }
    }
    //
    //public void writeLog(Box in, Box box, Method method) {
    //    String api = in.getNode(APIKey_Enum.API.getKey());
    //    //处理完将日志入库
    //    LogInfoService infoService = LogInfoService.getInstance();
    //    // String api = in.getNode(APIKey_Enum.API.getKey());
    //    MapNode data = in.getMapNode(APIKey_Enum.USER.getKey());
    //    logger.info("userInfo:\t" + JSON.toJSONString(data));
    //    String value = map.getValue(api);
    //    if (StringUtils.isNotBlank(value)) {
    //        String location = value.split(":")[0];
    //        String operation = value.split(":")[1];
    //        String level = value.split(":")[2];
    //        String content = "";
    //        if (!level.equals("1")) {
    //            content = JSON.toJSONString(in.getMapNode("data").toMap());
    //        } else {
    //            data.putNode("User_Id", getUserIdFromToken(box));
    //        }
    //
    //        Connection conn = PostgresqlConn.getConnection();
    //        try {
    //            infoService.insertLog(conn, data, location, operation, level, content);
    //        } catch (SQLException e) {
    //            logger.error("invoke--->" + in.getApi() + " error "
    //                    + ", arguments is " + in.toJson(), e);
    //        } finally {
    //            Dbink.close(conn);
    //        }
    //    }
    //}

    /**
     * if not have return null
     *
     * @param box
     */
    protected String getUserIdFromToken(Box box) {
        String userId = null;
        try {
            userId = box.getNode(APIKey_Enum.SSO.getKey());
        } catch (Exception e) {
            logger.error("没有SSO数据::\t" + JSON.toJSONString(box.toJson()));
            return null;// todo 查看为什么没有 sso
        }
        String userIdAndToken = AesRsjUtil.decrypt(userId);
        if (!StringUtils.isBlank(userIdAndToken)) {
            return userIdAndToken.split(":")[0];
        }
        logger.error("获取box 用户Id失败！");
        return null;
    }

    public Box handlerError(Box in, Error e) {
        // TODO error 处理
        logger.error("invoke--->" + in.getApi() + " error "
                + ", arguments is " + in.toJson(), e);
        return BoxUtil.errorBox(in, "服务器忙");
    }

    private Box handlerException(Box in, Exception e) {
        String errorCode = UUIDUtil.getUUID();
        loggerError(in, e, errorCode);
        return BoxUtil.errorBox(in, "服务器忙");
    }

    private Box handlerThink(Box in, ThinkException e) {
        String errorCode = UUIDUtil.getUUID();
        loggerError(in, e, errorCode);
        Box box = BoxUtil.errorBox(in, e.getMessage()).putMapNode(APIKey_Enum.EXCEPT.getKey(), e.toMapNode());
        logger.error(box.toJson());
        HashMap<String, String> jsonError = (HashMap<String, String>) box.toMap().get("_$except_");
        String $msg = jsonError.get("$msg");

        return BoxUtil.errorBox(in, "服务器忙");
    }

    private Box handlerBase(Box in, BaseException e) {
        String errorCode = UUIDUtil.getUUID();
        loggerError(in, e, errorCode);
        if (e instanceof RsjServiceWarnException) {// 前台处理逻辑，code码不同
            return BoxUtil.warnsBox(in, e.getMessage());
        }
        return BoxUtil.errorBox(in, "错误:" + errorCode + ":" + e.getMessage());
    }

    private void loggerError(Box in, Exception e, String errorCode) {
        logger.error("invoke--->" + in.getApi() + " error "
                + ", arguments is " + in.toJson() + ","
                + "UUID=" + errorCode, e);
    }

    protected Box executeLink(Box box) throws SQLException {
        return null;
    }


}
